﻿using System.Threading;

namespace LxCFD
{
    public class ThreadsMath
    {
        private static KahanSum _Sum1 = new KahanSum();
        private static KahanSum _Sum2 = new KahanSum();
        private static KahanSum _Sum3 = new KahanSum();
        public static void AddToSum(double toSum1)
        {
            lock (MultiThreads.GlobalLock)
            {
                _Sum1.Add(toSum1);
            }
        }
        public static void AddToSum(double toSum1, double toSum2)
        {
            lock (MultiThreads.GlobalLock)
            {
                _Sum1.Add(toSum1);
                _Sum2.Add(toSum2);
            }
        }
        public static void AddToSum(double toSum1, double toSum2, double toSum3)
        {
            lock (MultiThreads.GlobalLock)
            {
                _Sum1.Add(toSum1);
                _Sum2.Add(toSum2);
                _Sum3.Add(toSum3);
            }
        }
        public static void GetSum(out double sum1, out double sum2, out double sum3)
        {
            sum1 = _Sum1.GetSum();//   _sum1.GetSum(out sum1);
            sum2 = _Sum2.GetSum();// _sum2.GetSum(out sum2);
            sum3 = _Sum3.GetSum();// _sum3.GetSum(out sum3);
        }
        public static void AddTo(ref int target, int addend)
        {
            int initialValue, computedValue;
            do
            {
                initialValue = target;
                computedValue = initialValue + addend;
            }
            while (initialValue != Interlocked.CompareExchange(ref target, computedValue, initialValue));
        }
        public static void AddTo(ref double target, double addend)//由于多线程访问顺序不确定，可能会导致舍入误差，最终蝴蝶效应引起计算结果每次都相同，因此慎用该方法
        {
            double initialValue, computedValue;
            do
            {
                initialValue = target;
                if (double.IsNaN(initialValue)) return;//NaN ！= NaN,所以排除
                computedValue = initialValue + addend;
            }
            while (initialValue != Interlocked.CompareExchange(ref target, computedValue, initialValue));
        }
        public static void KeepMax(ref double target, double potentialMax)
        {
            double initialValue;
            do
            {
                initialValue = target;
                if (double.IsNaN(initialValue)) return;//NaN ！= NaN,所以排除
                if (potentialMax <= initialValue) return;
            }
            while (initialValue != Interlocked.CompareExchange(ref target, potentialMax, initialValue));
        }
        public static void KeepMin(ref double target, double potentialMin)
        {
            double initialValue;
            do
            {
                initialValue = target;
                if (double.IsNaN(initialValue)) return;//NaN ！= NaN,所以排除
                if (potentialMin >= initialValue) return;
            }
            while (initialValue != Interlocked.CompareExchange(ref target, potentialMin, initialValue));
        }
    }
}
